package fr.resasante.ldap;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import fr.resasante.exception.ApplicationException;

/**
 * Class used for querying in the LDAP
 * 
 * @author GEFFROY-DE-VILLEBLAN
 * 
 */
public class LdapSearch {
	/**
	 * The directory context
	 */
	private DirContext dirContext = null;

	/**
	 * Constructor
	 */
	public LdapSearch() {
		Hashtable<String, String> env = new Hashtable<String, String>();

		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		env.put(Context.PROVIDER_URL, "ldap://annuaire.gip-cps.fr:389");
		try {
			dirContext = new InitialDirContext(env);
		} catch (NamingException e) {
			throw new ApplicationException("Unable to connect to the LDAP server : "
					+ env.get(Context.PROVIDER_URL), e);
		}
	}

	/**
	 * Get a professional by its ADELI number and its postal code (there is no
	 * index on the AdeliNumber, so we need to limit the search for
	 * performances. Example of ADELI number : 134029297. In the LDAP the ADELI
	 * number is prefixed by a 0
	 * 
	 * @param adeliNumber
	 *            The ADELI number
	 * @param postalCode
	 *            The postal code
	 * @return The result containing all LDAP attributes
	 */
	public String getProfessionalByAdeliAsJson(String adeliNumber, String postalCode) {
		final String rootNode = "o=GIP-CPS,c=fr";
		SearchControls searchControls = new SearchControls();
		searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		NamingEnumeration<SearchResult> resultat;
		try {
			resultat = dirContext.search(rootNode, "(&(oldIdNat=0" + adeliNumber
					+ ")(postalCode=" + postalCode + ")(l=*))", searchControls);
		} catch (NamingException e) {
			throw new ApplicationException(
					"Unable to launch the search in the LDAP server. Does the node "
							+ rootNode + " exist ?", e);
		}
		try {
			if (resultat.hasMore()) {
				SearchResult sr = (SearchResult) resultat.next();
				LdapObject ldapObject = new LdapObject();
				ldapObject.fillPhysicalPerson(sr);
				return ldapObject.toJson();
			} else {
				return getProfessionalByRppsAsJson(adeliNumber, 0);
			}
		} catch (NamingException e) {
			throw new ApplicationException(
					"Unable to access the search result. Please check LDAP server rights.", e);
		}
	}

	/**
	 * Get a professional by its RPPS number. Example of RPPS number :
	 * 10001385219. In the LDAP the RPPS number is prefixed by a 8
	 * 
	 * @param rppsNumber
	 * @return
	 */
	public String getProfessionalByRppsAsJson(String rppsNumber) {
		return getProfessionalByRppsAsJson(rppsNumber, 8);
	}

	/**
	 * Get a professional by its RPPS number. Example of RPPS number :
	 * 10001385219.
	 * 
	 * @param rppsNumber
	 *            The RPPS number
	 * @param forcePrefix
	 *            The prefix of the number (used for ADELI cases)
	 * @return The result containing all LDAP attributes
	 */
	public String getProfessionalByRppsAsJson(String rppsNumber, int forcePrefix) {
		final String rootNode = "o=GIP-CPS,c=fr";
		SearchControls searchControls = new SearchControls();
		searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		NamingEnumeration<SearchResult> resultat;
		try {
			resultat = dirContext.search(rootNode, "(&(cn=" + forcePrefix + rppsNumber
					+ ")(l=*))", searchControls);
		} catch (NamingException e) {
			throw new ApplicationException(
					"Unable to launch the search in the LDAP server. Does the node "
							+ rootNode + " exist ?", e);
		}
		try {
			if (resultat.hasMore()) {
				SearchResult sr = (SearchResult) resultat.next();
				LdapObject ldapObject = new LdapObject();
				ldapObject.fillPhysicalPerson(sr);
				return ldapObject.toJson();
			}
		} catch (NamingException e) {
			throw new ApplicationException(
					"Unable to access the search result. Please check LDAP server rights.", e);
		}
		return "";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#finalize()
	 */
	protected void finalize() {
		try {
			dirContext.close();
		} catch (NamingException e) {
			throw new ApplicationException(
					"Unable to close the connection to the LDAP server", e);
		}
	}
}
